package cn.net.autocode.core.dycompile;

import javax.tools.*;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

public class DynamicCompile {

    private ClassLoader classLoader;

    public DynamicCompile(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    /**
     * 编译出类
     * @param fullClassName 全路径的类名
     * @param javaCode      java代码
     * @return 目标类
     */
    public Class<?> compileToClass(String fullClassName, String javaCode) throws Exception {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        //类加载器
        List<String> classpathEntries = new ArrayList<>();
        if (classLoader instanceof URLClassLoader) {
            URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
            for (URL url : urlClassLoader.getURLs()) {
                classpathEntries.add(new File(url.toURI()).getAbsolutePath());
            }
        }

        // 添加 Tomcat 的 lib 目录到类路径
        String tomcatLibPath = System.getProperty("catalina.base") + "/lib";
        File tomcatLibDir = new File(tomcatLibPath);
        if (tomcatLibDir.exists() && tomcatLibDir.isDirectory()) {
            for (File jarFile : tomcatLibDir.listFiles()) {
                if (jarFile.getName().endsWith(".jar")) {
                    classpathEntries.add(jarFile.getAbsolutePath());
                }
            }
        }

        // 构建类路径字符串
        StringBuilder classpath = new StringBuilder();
        for (String entry : classpathEntries) {
            if (classpath.length() > 0) {
                classpath.append(File.pathSeparator);
            }
            classpath.append(entry);
        }

        //类编辑
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
        ClassFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(diagnostics, null, null));

        List<JavaFileObject> jfiles = new ArrayList<>();
        jfiles.add(new CharSequenceJavaFileObject(fullClassName, javaCode));

        List<String> options = new ArrayList<>();
        options.add("-encoding");
        options.add("UTF-8");
        if(classpathEntries.size()>1){
            options.add("-classpath");
            options.add(classpath.toString());
        }

        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, jfiles);
        boolean success = task.call();

        if (success) {
            JavaClassObject jco = fileManager.getJavaClassObject();
            DynamicClassLoader dynamicClassLoader = new DynamicClassLoader(this.classLoader);
            //加载至内存
            return dynamicClassLoader.loadClass(fullClassName, jco);
        } else {
            for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
                String error = compileError(diagnostic);
                throw new RuntimeException(error);
            }
            throw new RuntimeException("compile error");
        }
    }

    private String compileError(Diagnostic diagnostic) {
        StringBuilder res = new StringBuilder();
        res.append("LineNumber:[").append(diagnostic.getLineNumber()).append("]\n");
        res.append("ColumnNumber:[").append(diagnostic.getColumnNumber()).append("]\n");
        res.append("Message:[").append(diagnostic.getMessage(null)).append("]\n");
        return res.toString();
    }
}
